'''
    Code Name: Python Move Character 3D
    
    Module: PyMoveCharacter
    Filename:  __init__.py
    
    Developed by: Juan C. Montes
    
    Created on 27/03/2009
'''


# Referencias de OGRE
import ogre.renderer.OGRE as ogre
import ogre.io.OIS as ois


# Referencias del proyecto
from PyMoveCharacter import Character


''' Clase principal del juego '''
class PyMoveCharacter(ogre.FrameListener):    
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: Constructor
    '''
    def __init__(self):
        # Definimos los objetos de la clase
        self.camera = ogre.Camera
        self.scenemanager = ogre.SceneManager
        self.pViewport = ogre.Viewport
        self.light = ogre.Light
        self.inputManager = ois.InputManager
        self.keyboard = ois.Keyboard
        self.mouse = ois.Mouse
        
        # Inicializamos variables
        self.pause = False
        self.time = 0
        self.quit = False
        
    
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: run
    Descript: Funcion principal de carga del engine
    '''
    def run(self):
        self.createRoot()
        self.setupRenderSystem()
        self.createRenderWindow()        
        self.setupScene()
        self.setupInputSystem()
        self.createFrameListener()
        self.initialiseResourceGroups()        
        self.createScene()
        self.startRenderLoop()


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: createRoot
    Descript: Creamos la raiz del engine
    '''    
    def createRoot(self):
        self.root = ogre.Root()


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: setupRenderSystem
    Descript: Cargamos la config o usamos la que ya tenemos
    '''    
    def setupRenderSystem(self):
        if not self.root.restoreConfig() and not self.root.showConfigDialog():
            raise Exception("User canceled the config dialog!" 
                            "-> Application.setupRenderSystem()")


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: createRenderWindow
    Descript: Creamos la ventana principal
    '''  
    def createRenderWindow(self):
        self.window = self.root.initialise(True, "Python Move Character 3D")


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: initialiseResourceGroups
    Descript: Cargamos los recursos del juego
    '''  
    def initialiseResourceGroups(self):
        ogre.ResourceGroupManager.getSingleton().addResourceLocation(
                "./media/", "FileSystem", "PyMoveCharacter")
        ogre.ResourceGroupManager.getSingleton().initialiseAllResourceGroups()


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: setupScene
    Descript: Preparamos la escena cargando camaras, luces, viewports...
    '''  
    def setupScene(self):
        # Creamos el SceneManager        
        self.scenemanager = self.root.createSceneManager(ogre.ST_EXTERIOR_CLOSE)
        
        # Creamos y posicionamos la camara principal        
        self.camera = self.scenemanager.createCamera("MainCamera")
        self.camera.setPosition(0, 300, 400)
        self.camera.lookAt(0, 0, 0)
        self.camera.setNearClipDistance(5)
        self.camera.setFarClipDistance(1000)
        
        # Creamos el punto de vista basado en la camara
        self.pViewport = self.window.addViewport(self.camera)
        self.pViewport.setBackgroundColour(ogre.ColourValue(0, 0, 0))
        self.camera.setAspectRatio(self.pViewport.getActualWidth() / 
                                   self.pViewport.getActualHeight())
        
        # Ajustamos la luz general de la escena
        self.scenemanager.setAmbientLight(ogre.ColourValue(0.75, 0.75, 0.75))
        
        # Creamos un punto de luz    
        self.light = self.scenemanager.createLight("Light")
        self.light.setPosition(0, 0, 50)


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: setupInputSystem
    Descript: Preparamos los controles del teclado
    ''' 
    def setupInputSystem(self):
        windowHandle = 0
        renderWindow = self.root.getAutoCreatedWindow()
        windowHandle = renderWindow.getCustomAttributeInt("WINDOW")
        paramList = [("WINDOW", str(windowHandle))]        
        self.inputManager = ois.createPythonInputSystem(paramList)
        try:
            self.keyboard = self.inputManager.createInputObjectKeyboard(
                            ois.OISKeyboard, True)
            self.mouse = self.inputManager.createInputObjectMouse(
                         ois.OISMouse, True)
        except Exception, e:
            raise e


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: createFrameListener
    Descript: Iniciamos el listener principal y del teclado
    ''' 
    def createFrameListener(self):
        ogre.FrameListener.__init__(self)
        self.root.addFrameListener(self)
        

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: startRenderLoop
    Descript: Iniciamos el engine
    ''' 
    def startRenderLoop(self):
        self.root.startRendering()


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: cleanUp
    Descript: Destruimos los objetos que hagan falta
    ''' 
    def cleanUp(self):
        pass
        
                
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Destructor
    ''' 
    def __del__(self):
        self.cleanUp()
        pass
            
        
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: createScene
    Descript: Crea la escene inicial
    ''' 
    def createScene(self):
        # Creamos el suelo
        self.scenemanager.setWorldGeometry("terrain.cfg")
        
        # Creamos el PJ
        self.char = Character.Character(self.scenemanager, "Ninja")
        self.char.addToScene(self.camera)


    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: frameStarted
    Descript: Control del inicio del render
    ''' 
    def frameStarted(self, e):
        # Control para que si cierran la ventana se acabe el render
        if self.window.isClosed():
            self.quit = True
            return False                
        
        # Capturamos el teclado y el raton
        self.keyboard.capture()
        self.mouse.capture()
        
        # Control de la actualizacion del PJ
        if self.char:
            self.char.updateChar(e.timeSinceLastFrame, 
                                 self.keyboard, self.mouse)
        
        # Control del buffer de teclas
        if self.keyboard.buffered():
            self.processKeyInput()                
            
        # Control del raton
        if self.mouse.buffered():
            self.processMouseInput()
            
        # Ponemos un limite de tiempo a la pausa de 4s
        if self.time < 4:
            self.time += e.timeSinceLastFrame
        else:
            self.wait = False
            self.time = 0
                            
        return not self.quit
    

    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: processKeyInput
    Descript: Control de la pulsacion de las teclas
    ''' 
    def processKeyInput(self):
        # Controlamos que el juego no este parado
        if not self.pause:
            # Controlamos la pulsacion de las teclas
            if self.keyboard.isKeyDown(ois.KC_ESCAPE):
                self.quit = True
                self.root.shutdown()
            elif self.keyboard.isKeyDown(ois.KC_P):
                self.pause = True
        else:
            if self.keyboard.isKeyDown(ois.KC_R):
                self.pause = False
        
        return True
  
  
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Function: processMouseInput
    Descript: Control del raton
    ''' 
    def processMouseInput(self):
        # Controlamos la rotacion del raton con el boton derecho pulsado
        if not self.pause:
            mouseState = self.mouse.getMouseState()
            if mouseState.buttonDown(ois.MB_Right):
                self.rotX = ogre.Degree(-mouseState.X.rel * 0.13)
                self.rotY = ogre.Degree(-mouseState.Y.rel * 0.13) 
        
        return True
                
                
                
                